/*******************************************************************************
型号	  Byte容量	  页数	  页内字节数    WORD_ADDR位数 WORD_ADDR字节数
x24C01	  128Byte	  16页	  8Byte			7bit			1Byte
x24C02	  256Byte	  32页	  8Byte			8bit			1Byte
x24C04	  512Byte	  32页	  16Byte		9bit			1Byte
x24C08	  1024Byte	  64页	  16Byte		10bit			1Byte
x24C16	  2048Byte	  128页	  16Byte		11bit			1Byte
x24C32	  4096Byte	  128页	  32Byte		12bit			2Byte
x24C64	  8192Byte	  256页	  32Byte		13bit			2Byte
x24C128	  16384Byte	  256页	  64Byte		14bit			2Byte
x24C256	  32768Byte	  512页	  64Byte		15bit			2Byte
x24C512	  65536Byte	  512页	  128Byte		16bit			2Byte
*******************************************************************************/

#include "iic.h"
#include "eeprom.h"
#include "systick.h"

#define READ_CMD 1
#define WRITE_CMD 0

#define x24C08 // 器件名称，x24C01~x24C512
// #define x24C64

#define DEV_ADDR 0xA0 // 设备硬件地址

#ifdef x24C01
#define PAGE_NUM 16                          // 页数
#define PAGE_SIZE 8                          // 页面大小(字节)
#define CAPACITY_SIZE (PAGE_NUM * PAGE_SIZE) // 总容量(字节)
#define ADDR_BYTE_NUM 1                      // 地址字节个数
#endif

#ifdef x24C02
#define PAGE_NUM 32                          // 页数
#define PAGE_SIZE 8                          // 页面大小(字节)
#define CAPACITY_SIZE (PAGE_NUM * PAGE_SIZE) // 总容量(字节)
#define ADDR_BYTE_NUM 1                      // 地址字节个数
#endif

#ifdef x24C04
#define PAGE_NUM 32                          // 页数
#define PAGE_SIZE 16                         // 页面大小(字节)
#define CAPACITY_SIZE (PAGE_NUM * PAGE_SIZE) // 总容量(字节)
#define ADDR_BYTE_NUM 1                      // 地址字节个数
#endif

#ifdef x24C08
#define PAGE_NUM 64                          // 页数
#define PAGE_SIZE 16                         // 页面大小(字节)
#define CAPACITY_SIZE (PAGE_NUM * PAGE_SIZE) // 总容量(字节)
#define ADDR_BYTE_NUM 1                      // 地址字节个数
#endif

#ifdef x24C16
#define PAGE_NUM 128                         // 页数
#define PAGE_SIZE 16                         // 页面大小(字节)
#define CAPACITY_SIZE (PAGE_NUM * PAGE_SIZE) // 总容量(字节)
#define ADDR_BYTE_NUM 1                      // 地址字节个数
#endif

#ifdef x24C32
#define PAGE_NUM 128                         // 页数
#define PAGE_SIZE 32                         // 页面大小(字节)
#define CAPACITY_SIZE (PAGE_NUM * PAGE_SIZE) // 总容量(字节)
#define ADDR_BYTE_NUM 2                      // 地址字节个数
#endif

#ifdef x24C64
#define PAGE_NUM 256                         // 页数
#define PAGE_SIZE 32                         // 页面大小(字节)
#define CAPACITY_SIZE (PAGE_NUM * PAGE_SIZE) // 总容量(字节)
#define ADDR_BYTE_NUM 2                      // 地址字节个数
#endif

#ifdef x24C128
#define PAGE_NUM 256                         // 页数
#define PAGE_SIZE 64                         // 页面大小(字节)
#define CAPACITY_SIZE (PAGE_NUM * PAGE_SIZE) // 总容量(字节)
#define ADDR_BYTE_NUM 2                      // 地址字节个数
#endif

#ifdef x24C256
#define PAGE_NUM 512                         // 页数
#define PAGE_SIZE 64                         // 页面大小(字节)
#define CAPACITY_SIZE (PAGE_NUM * PAGE_SIZE) // 总容量(字节)
#define ADDR_BYTE_NUM 2                      // 地址字节个数
#endif

#ifdef x24C512
#define PAGE_NUM 512                         // 页数
#define PAGE_SIZE 128                        // 页面大小(字节)
#define CAPACITY_SIZE (PAGE_NUM * PAGE_SIZE) // 总容量(字节)
#define ADDR_BYTE_NUM 2                      // 地址字节个数
#endif

void x24CxxInit()
{
    IIC_Init();
}

uint8_t x24CxxPageSize()
{
    return PAGE_SIZE;
}

uint8_t x24CxxPageNum()
{
    return PAGE_NUM;
}

void x24CxxWriteByte(uint16_t u16Addr, uint8_t u8Data)
{
    // x24Cxx_WriteEnable();//使能写入
    IIC_Start();         // 起始信号
#if (ADDR_BYTE_NUM == 1) // 地址只有1个字节
    {
        IIC_WriteByte(DEV_ADDR | WRITE_CMD | (((uint8_t)((u16Addr >> 8) & 0x07)) << 1)); // 器件寻址+写+页选择位
        IIC_WaitAck();                                                                   // 等待应答
        IIC_WriteByte((uint8_t)(u16Addr & 0xFF));                                        // 只取地址的低字节
        IIC_WaitAck();                                                                   // 等待应答
    }
#endif
#if (ADDR_BYTE_NUM == 2) // 地址有2个字节
    {
        IIC_WriteByte(DEV_ADDR | WRITE_CMD);             // 器件寻址+写
        IIC_WaitAck();                                   // 等待应答
        IIC_WriteByte((uint8_t)((u16Addr >> 8) & 0xFF)); // 地址高字节
        IIC_WaitAck();                                   // 等待应答
        IIC_WriteByte((uint8_t)(u16Addr & 0xFF));        // 地址低字节
        IIC_WaitAck();                                   // 等待应答
    }
#endif
    IIC_WriteByte(u8Data);
    IIC_WaitAck(); // 等待应答
    IIC_Stop();
    // x24Cxx_WriteDisble();//禁止写入
}

uint8_t x24CxxReadByte(uint16_t u16Addr)
{
    uint8_t u8Data = 0;
    IIC_Start();         // 起始信号
#if (ADDR_BYTE_NUM == 1) // 地址只有1个字节
    {
        IIC_WriteByte(DEV_ADDR | WRITE_CMD | (((uint8_t)((u16Addr >> 8) & 0x07)) << 1)); // 器件寻址+写+页选择位
        if (IIC_WaitAck())                                                               // 等待应答
        {
            IIC_Stop();
            return 0;
        }
        IIC_WriteByte((uint8_t)(u16Addr & 0xFF)); // 只取地址的低字节
        IIC_WaitAck();                            // 等待应答
    }
#endif
#if (ADDR_BYTE_NUM == 2) // 地址有2个字节
    {
        IIC_WriteByte(DEV_ADDR | WRITE_CMD); // 器件寻址+写
        if (IIC_WaitAck())                   // 等待应答
        {
            IIC_Stop();
            return 0;
        }
        IIC_WriteByte((uint8_t)((u16Addr >> 8) & 0xFF)); // 地址高字节
        IIC_WaitAck();                                   // 等待应答
        IIC_WriteByte((uint8_t)(u16Addr & 0xFF));        // 地址低字节
        IIC_WaitAck();                                   // 等待应答
    }
#endif
    IIC_Start();                        // 起始信号
    IIC_WriteByte(DEV_ADDR | READ_CMD); // 器件寻址+读
    IIC_WaitAck();                      // 等待应答
    u8Data = IIC_ReadByte();
    IIC_NoAck();
    IIC_Stop();
    return u8Data;
}

void x24CxxWritePage(uint16_t u16Addr, uint8_t u8Len, uint8_t *pData)
{
    uint8_t i;
    if (u8Len > PAGE_SIZE) // 长度大于页的长度
    {
        u8Len = PAGE_SIZE;
    }
    if ((u16Addr + (uint16_t)u8Len) > CAPACITY_SIZE) // 超过容量
    {
        u8Len = (uint8_t)(CAPACITY_SIZE - u16Addr);
    }
    if (((u16Addr % PAGE_SIZE) + (uint16_t)u8Len) > PAGE_SIZE) // 判断是否跨页
    {
        u8Len -= (uint8_t)((u16Addr + (uint16_t)u8Len) % PAGE_SIZE); // 跨页，截掉跨页的部分
    }
    IIC_Start();         // 起始信号
#if (ADDR_BYTE_NUM == 1) // 地址只有1个字节
    {
        IIC_WriteByte(DEV_ADDR | WRITE_CMD | (((uint8_t)((u16Addr >> 8) & 0x07)) << 1)); // 器件寻址+写+页选择位
        if (IIC_WaitAck())                                                               // 等待应答
        {
            IIC_Stop();
            return;
        }
        IIC_WriteByte((uint8_t)(u16Addr & 0xFF)); // 只取地址的低字节
        IIC_WaitAck();                            // 等待应答
    }
#endif
#if (ADDR_BYTE_NUM == 2) // 地址有2个字节
    {
        IIC_WriteByte(DEV_ADDR | WRITE_CMD); // 器件寻址+写
        if (IIC_WaitAck())                   // 等待应答
        {
            IIC_Stop();
            return;
        }
        IIC_WriteByte((uint8_t)((u16Addr >> 8) & 0xFF)); // 地址高字节
        IIC_WaitAck();                                   // 等待应答
        IIC_WriteByte((uint8_t)(u16Addr & 0xFF));        // 地址低字节
        IIC_WaitAck();                                   // 等待应答
    }
#endif
    for (i = 0; i < u8Len; i++)
    {
        IIC_WriteByte(*(pData + i));
        IIC_WaitAck(); // 等待应答
    }

    IIC_Stop();
}

void x24CxxReadPage(uint16_t u16Addr, uint8_t u8Len, uint8_t *pBuff)
{
    uint8_t i;
    if (u8Len > PAGE_SIZE) // 长度大于页的长度
    {
        u8Len = PAGE_SIZE;
    }
    if ((u16Addr + (uint16_t)u8Len) > CAPACITY_SIZE) // 超过容量
    {
        u8Len = (uint8_t)(CAPACITY_SIZE - u16Addr);
    }
    if (((u16Addr % PAGE_SIZE) + (uint16_t)u8Len) > PAGE_SIZE) // 判断是否跨页
    {
        u8Len -= (uint8_t)((u16Addr + (uint16_t)u8Len) % PAGE_SIZE); // 跨页，截掉跨页的部分
    }
    IIC_Start();         // 起始信号
#if (ADDR_BYTE_NUM == 1) // 地址只有1个字节
    {
        IIC_WriteByte(DEV_ADDR | WRITE_CMD | (((uint8_t)((u16Addr >> 8) & 0x07)) << 1)); // 器件寻址+写+页选择位
        IIC_WaitAck();                                                                   // 等待应答
        IIC_WriteByte((uint8_t)(u16Addr & 0xFF));                                        // 只取地址的低字节
        IIC_WaitAck();                                                                   // 等待应答
    }
#endif
#if (ADDR_BYTE_NUM == 2) // 地址有2个字节
    {
        IIC_WriteByte(DEV_ADDR | WRITE_CMD);             // 器件寻址+写
        IIC_WaitAck();                                   // 等待应答
        IIC_WriteByte((uint8_t)((u16Addr >> 8) & 0xFF)); // 地址高字节
        IIC_WaitAck();                                   // 等待应答
        IIC_WriteByte((uint8_t)(u16Addr & 0xFF));        // 地址低字节
        IIC_WaitAck();                                   // 等待应答
    }
#endif
    IIC_Start();                        // 起始信号
    IIC_WriteByte(DEV_ADDR | READ_CMD); // 器件寻址+读
    IIC_WaitAck();                      // 等待应答
    for (i = 0; i < (u8Len - 1); i++)
    {
        *(pBuff + i) = IIC_ReadByte();
        IIC_Ack();
    }
    *(pBuff + u8Len - 1) = IIC_ReadByte();
    IIC_NoAck(); // 最后一个不应答
    IIC_Stop();
}

void x24CxxWriteBuffer(uint16_t write_address, uint8_t number_of_byte, uint8_t *p_buffer)
{
    uint8_t number_of_page = 0, number_of_single = 0, address = 0, count = 0;
    uint8_t I2C_PAGE_SIZE = x24CxxPageSize();

    address = write_address % I2C_PAGE_SIZE;
    count = I2C_PAGE_SIZE - address;
    number_of_page =  number_of_byte / I2C_PAGE_SIZE;
    number_of_single = number_of_byte % I2C_PAGE_SIZE;

    /* if write_address is I2C_PAGE_SIZE aligned  */
    if (0 == address) {
        while(number_of_page--) {
            // eeprom_page_write(p_buffer, write_address, I2C_PAGE_SIZE);
            x24CxxWritePage(write_address, I2C_PAGE_SIZE, p_buffer);
            // eeprom_wait_standby_state();
            delay_1ms(6);
            write_address +=  I2C_PAGE_SIZE;
            p_buffer += I2C_PAGE_SIZE;
        }
        if(0 != number_of_single) {
            // eeprom_page_write(p_buffer, write_address, number_of_single);
            x24CxxWritePage(write_address, number_of_single, p_buffer);
            // eeprom_wait_standby_state();
            delay_1ms(6);
        }
    } else {
        /* if write_address is not I2C_PAGE_SIZE aligned */
        if(number_of_byte < count) {
            x24CxxWritePage(write_address, number_of_byte, p_buffer);
            delay_1ms(6);
            // eeprom_wait_standby_state();
        } else {
            number_of_byte -= count;
            number_of_page =  number_of_byte / I2C_PAGE_SIZE;
            number_of_single = number_of_byte % I2C_PAGE_SIZE;

            if(0 != count) {
                // eeprom_page_write(p_buffer, write_address, count);
                x24CxxWritePage(write_address, count, p_buffer);
                // eeprom_wait_standby_state();
                delay_1ms(6);
                write_address += count;
                p_buffer += count;
            }
            /* write page */
            while(number_of_page--) {
                // eeprom_page_write(p_buffer, write_address, I2C_PAGE_SIZE);
                x24CxxWritePage(write_address, I2C_PAGE_SIZE, p_buffer);
                // eeprom_wait_standby_state();
                delay_1ms(6);
                write_address +=  I2C_PAGE_SIZE;
                p_buffer += I2C_PAGE_SIZE;
            }
            /* write single */
            if(0 != number_of_single) {
                // eeprom_page_write(p_buffer, write_address, number_of_single);
                x24CxxWritePage(write_address, number_of_single, p_buffer);
                // eeprom_wait_standby_state();
                delay_1ms(6);
            }
        }
    }
}

void x24CxxReadBuffer(uint16_t read_address, uint8_t number_of_byte, uint8_t *p_buffer)
{
    uint8_t number_of_page = 0, number_of_single = 0, address = 0, count = 0;
    uint8_t I2C_PAGE_SIZE = x24CxxPageSize();

    address = read_address % I2C_PAGE_SIZE;
    count = I2C_PAGE_SIZE - address;
    number_of_page =  number_of_byte / I2C_PAGE_SIZE;
    number_of_single = number_of_byte % I2C_PAGE_SIZE;

    if (0 == address)
    {
        while (number_of_page--)
        {
            x24CxxReadPage(read_address, I2C_PAGE_SIZE, p_buffer);
            delay_1ms(6);
            read_address += I2C_PAGE_SIZE;
            p_buffer += I2C_PAGE_SIZE;
        }
        if(0 != number_of_single) {
            x24CxxReadPage(read_address, number_of_single, p_buffer);
            delay_1ms(6);
        }
    }
    else
    {
        /* if write_address is not I2C_PAGE_SIZE aligned */
        if(number_of_byte < count) {
            x24CxxReadPage(read_address, number_of_byte, p_buffer);
            delay_1ms(6);
        } else {
            number_of_byte -= count;
            number_of_page = number_of_byte / I2C_PAGE_SIZE;
            number_of_single = number_of_byte % I2C_PAGE_SIZE;

            if(0 != count) {
                x24CxxReadPage(read_address, count, p_buffer);
                delay_1ms(6);
                read_address += count;
                p_buffer += count;
            }
            /* write page */
            while(number_of_page--) {
                x24CxxWritePage(read_address, I2C_PAGE_SIZE, p_buffer);
                delay_1ms(6);
                read_address += I2C_PAGE_SIZE;
                p_buffer += I2C_PAGE_SIZE;
            }
            /* write single */
            if(0 != number_of_single) {
                x24CxxWritePage(read_address, number_of_single, p_buffer);
                delay_1ms(6);
            }
        }
    }
}